/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package phd.dupenois.changeidentifiers.algorithms.chihull;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.Vector;
import phd.dupenois.changeidentifiers.algorithms.chihull.display.ChiHullGrid;
import uk.co.dupenois.geometry.Coordinate;
import uk.co.dupenois.geometry.Edge;
import uk.co.dupenois.geometry.combinatorialmap.CombinatorialMap;
import uk.co.dupenois.geometry.combinatorialmap.CombinatorialMapException;

/**
 *
 * @author mpd209
 */
public class ChiHullEngine {

    public static long PAUSE = 0;

    private TreeSet<Edge> boundaryEdges;
    private CombinatorialMap combinatorialMap;
    private double lengthParameter;
    private ChiHullGrid grid;
    private Edge[] edges;
    public ChiHullEngine(double lengthParameter, Edge[] edges){
        this(lengthParameter, edges, null);
    }
    public ChiHullEngine(double lengthParameter, Edge[] edges, ChiHullGrid grid){
        this.lengthParameter = lengthParameter;
        this.grid = grid;
        this.edges =edges;
    }


    public CombinatorialMap generateChiHull() throws CombinatorialMapException{

//        if(isDebug()){
//            this.grid.drawTriangulation(edges);
//            debugOut("Drawn Triangulation");
//            pause();
//        }

        combinatorialMap = CombinatorialMap.createCombinatorialMap(edges);
//        if(isDebug()){
//            this.grid.drawChiHull(combinatorialMap.getEdges());
//            debugOut("Drawn Start Chi Hull");
//            pause();
//        }

        boundaryEdges = new TreeSet<Edge>(combinatorialMap.getEdgeComparator());
        boundaryEdges.addAll(Arrays.asList(combinatorialMap.getBoundaryEdges()));

        Edge validRemoveEdge = getValidRemovalEdge();
        CombinatorialMap.RevealFunctionResult revealedEdges;
//        int i = 0;
        while(validRemoveEdge!=null){
//            if(isDebug()){
//                debugOut("Valid Remove Edge "+validRemoveEdge.getStart()+"->"+validRemoveEdge.getFinish());
//                this.grid.drawValidRemovalEdge(validRemoveEdge);
//                pause();
//            }
            revealedEdges = combinatorialMap.removeEdge(validRemoveEdge);
            boundaryEdges.add(revealedEdges.getEdge1());
            boundaryEdges.add(revealedEdges.getEdge2());
//            if(isDebug()){
//                i++;
//                debugOut("Times passed Through: "+i);
//                this.grid.drawChiHull(combinatorialMap.getEdges());
//                pause();
//            }
            validRemoveEdge = getValidRemovalEdge();
        }
//        if(isDebug()){
//            this.grid.drawChiHull(combinatorialMap.getEdges());
//            debugOut("Drawn Finished Chi Hull");
//            pause();
//        }
//        if(isDebug()){
//            this.grid.drawFootprint(combinatorialMap);
//            debugOut("Drawn Finished Footprint");
//            pause();
//        }
        return combinatorialMap;
    }

     public Edge getValidRemovalEdge(){
        //Must be simple polygon, must contains all point of P
        //and bounds an area contained within (possibly equal) to the
        //convex hull of p
        if(boundaryEdges.size()<1) return null;
        Iterator<Edge> iter = boundaryEdges.iterator();
        Edge validEdge =null;
        Edge edge =null;
        while(validEdge==null&&iter.hasNext()){
            edge = iter.next();
            iter.remove();
            if(edge.length()>=lengthParameter && regularIfRemoved(edge)){
                validEdge = edge;
            }
        }
        return validEdge;
    }
    public boolean regularIfRemoved(Edge edge){
        Coordinate revealedVertex = combinatorialMap.revealFunction(edge).getCommonVertex();
//        if(isDebug()){
//            debugOut("Checking "+revealedVertex+": is on boundary = "+combinatorialMap.isVertexOnBoundary(revealedVertex));
//            pause();
//        }
        return !(combinatorialMap.isVertexOnBoundary(revealedVertex));
    }
    public DelaunayTriangulation constructDelaunayTriangulation(Vector<Coordinate> list){
        ArrayList<Coordinate> arrayList = new ArrayList<Coordinate>();
        arrayList.addAll(list);
        DivideAndConquerDelaunayTriangulationEngine engine =
                new DivideAndConquerDelaunayTriangulationEngine(arrayList, true);
        return engine.triangulate();
    }



//    private static void pause(){
//        pause(PAUSE);
//    }
//    private static void pause(long amount){
//        try{
//            Thread.sleep(amount);
//        }catch(InterruptedException ex){}
//    }
//
//    public boolean isDebug(){
////        return false;
//        return (this.grid!=null);
//    }
//    public void debugOut(String debug){
////        if(isDebug()) System.out.println(debug);
//    }

}
